﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using FXnaGis;

using DotSpatial.Topology;



namespace NSCore
{
    /// <summary>
    /// 障碍物引起的衰减
    /// </summary>
    public class ABar:Attenuation,IABar
    {

        public ABar(NSData data):base(data)
        { 


        }



        public double Compute(MathReceptor receptor,MathPS ps)
        {


            //这里我们需要知道接受点与污染源之间的直线

            //LineString lsRP = new LineString(new List<Coordinate> {receptor.Coord,ps.Coord });



            //测算距离

            double r = receptor.Coord.Distance(ps.Coord);
                



            //这里必须保证，不含有Z坐标，才行，真郁闷



            Coordinate cReceptor2D=new Coordinate ();
            cReceptor2D.X=receptor.Coord.X;
            cReceptor2D.Y=receptor.Coord.Y;


            Coordinate cPs2D=new Coordinate ();
            cPs2D.X=ps.Coord.X;
            cPs2D.Y=ps.Coord.Y;


            


            LineString lsRP = new LineString(new List<Coordinate> {cReceptor2D,cPs2D});




            List<Barrier> lstBarrier = new List<Barrier>();



         




            //查找所有的相交的barrier,
            //然后逐个计算衰减影响


            //发现直接利用三维物体碰撞算法，是非常复杂的事情
            
            //那么我们是否可以换个角度，
            //由于这里我们假定屏障是垂直的，那么我们是否可以先通过平面投影计算相交特点，之后再加入对于高度的验算
            //来设定具体的值呢




            //投影相交测试之后

            //分别表示声程差

            //这里先写一些测试用的伪代码



            //写了好多伪代码，这里我们假设使用影响最大的一个屏障，也即声程差最大的，左，上，右，都取最大的


            double dTop = 0, dLeft = 0, dRight = 0;




            foreach (FShape  item in this.Data.BarrierLayer.Shapes.Values)
            {
                Barrier b = item as Barrier;

                //如果存在交线

                if (b.InnerShape.Line.Intersects(lsRP))
                {

                    Point p = b.InnerShape.Line.Intersection(lsRP) as Point;



                    //暂时先这样写吧

                    if (p==null)
                    {
                        continue ;
                        
                    }




                    //计算相交点的高度,利用平面投影距离比


                    double disReceptor = cReceptor2D.Distance(p.Coordinate);


                  

                    double disPs = cPs2D.Distance(p.Coordinate);

                    double height = disReceptor / (disReceptor + disPs) * (ps.Coord.Z - receptor.Coord.Z);


                    //如果高度也合适
                    if (Math.Abs(height)<b.Height)
                    {

                        Coordinate cTemp = new Coordinate(p.Coordinate.X,p.Coordinate.Y,height);




                        double d = cTemp.Distance(receptor.Coord) + cTemp.Distance(ps.Coord) - r;

                        if (dTop<d)
                        {
                            dTop = d;
                            
                        }


                        lstBarrier.Add(b);

                        
                    }


                  

                    


                   

                }
                
            }





            //测试是否有屏障，如果没有，就返回

            if (lstBarrier.Count==0)
            {
                return 0;

                
            }







            Vector vRP = new Vector(receptor.Coord, ps.Coord);

            double angleMax=double.MinValue;
            double angleMin=double .MaxValue;

            Coordinate cMax;
            Coordinate cMin;




            //这里我们先向办法，计算所有屏障的外围连接线



            foreach (Barrier b in lstBarrier)
            {


                //通过最大夹角的方法，我们计算声程，想要详细有效，可能需要借助dotspatial

                foreach (Coordinate c in b.InnerShape.Line.Coordinates)
                {

                    Vector vTemp = new Vector(receptor.Coord,c);

                    double angle = Math.Acos(Vector.DotProduct(vRP, vTemp) / (vRP.Length + vTemp.Length));


                    if (angleMin>angle)
                    {
                        angleMin = angle;

                        cMin = c.Clone() as Coordinate;
                        
                    }



                    if (angleMax<angle)
                    {

                        angleMax = angle;

                        cMax = c.Clone() as Coordinate;

                        
                    }


                }
 


                
            }



            //之后我们就可以循环所有障碍物，取得实际取作用的障碍是谁



            //这里我们先用第一个做实验数据，并且认为声屏障不是无限长的





           




            //这里学习到了一个公式
            //频率*波长=速度，速度一般取340 ，

            //340、500=波长，波长单位为米



            //这里默认使用500，我们之后会改变，通过参数传入


            double waveLength = 340 / 500;




            //分别表示菲涅尔数

            double nTop=0, nLeft=0, nRight=0;




            nTop = 2 * dTop / waveLength;

            nLeft = 2 * dLeft / waveLength;

            nRight = 2 * dRight / waveLength;



    





            //无限长
            if (false)
            {

                return -10 * Math.Log10(1 / (3 + 20 * nTop));

            }

            else
            {
                //不是无限长的情况


                return -10 * Math.Log10(1 / (3 + 20 * nTop) + 1 / (3 + 20 * nLeft) + 1 / (3 + 20 * nRight));
 
            }


          




           
            
        }
    }
}
